#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
XBot客户端主程序 - 集成管理后台版本
"""

import asyncio
import json
import os
import re
import sys
import time
import websockets
import threading
import requests
from typing import Dict, List, Optional, Any
import importlib.util
import glob
from datetime import datetime

from api.xbot.friend_api import FriendApi
from common.logger import logger
from common.config import Config
from common.config_manager import config_manager
from api.xbot.login_api import LoginApi
from api.xbot.msg_api import MsgApi
from database.messsagDB import MessageDB, Message, FriendInfo
from plugins.plugin_manager import PluginManager

# 导入管理后台相关模块
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'admin_web'))
from admin_web.app import app as admin_app, wechat_login_status, check_wechat_login_status


class XBotClient:
    """XBot客户端主类 - 集成管理后台"""
    
    def __init__(self):
        self.config = Config()
        # 从配置文件获取URL
        self.base_url = config_manager.api_config.api_base_url
        self.ws_url = config_manager.api_config.websocket_url
        self.wxid = ""
        self.is_logged_in = False
        self.websocket = None
        self.login_api = LoginApi.init_no_wxid(self.base_url)
        self.msg_api = None
        self.db = MessageDB()
        self.plugin_manager = PluginManager()
        self.admin_thread = None
        self.reconnect_interval = 5  # 重连间隔（秒）
        self.max_reconnect_attempts = 10  # 最大重连次数
        self.current_reconnect_attempt = 0  # 当前重连次数
        self.running = False  # 运行状态标志

        logger.info(f"API基础URL: {self.base_url}")
        logger.info(f"WebSocket URL: {self.ws_url}")

    async def initialize(self):
        """初始化客户端"""
        logger.info("正在初始化XBot客户端...")
        
        # 初始化数据库
        await self.db.initialize()
        
        # 加载插件
        await self.plugin_manager.load_plugins()
        logger.info("XBot客户端初始化完成")

    
    async def check_login_status_from_admin(self) -> bool:
        """从管理后台检查登录状态"""
        try:
            # 直接调用管理后台的检查函数，而不是HTTP请求
            from admin_web.app import check_wechat_login_status
            
            # 检查登录状态
            status = check_wechat_login_status()
            
            if status.get("is_logged_in") and status.get("wxid"):
                self.wxid = status["wxid"]
                self.is_logged_in = True
                logger.info(f"检测到已登录状态，wxid: {self.wxid}")
                return True
            
            logger.info("检测到未登录状态")
            return False
            
        except Exception as e:
            logger.error(f"检查登录状态失败: {e}")
            return False
    
    async def wait_for_login(self):
        """等待管理后台完成登录"""
        logger.info("等待管理后台完成微信登录...")
        max_wait_time = 300  # 最多等待5分钟
        check_interval = 10  # 每10秒检查一次
        elapsed_time = 0
        
        while elapsed_time < max_wait_time:
            if await self.check_login_status_from_admin():
                logger.info("检测到登录成功！")
                return True
            
            await asyncio.sleep(check_interval)
            elapsed_time += check_interval
            logger.info(f"等待登录中... ({elapsed_time}/{max_wait_time}秒)")
        
        logger.error("等待登录超时")
        return False
    
    async def connect_websocket(self):
        """连接WebSocket"""
        try:
            if not self.wxid:
                logger.error("未登录，无法连接WebSocket")
                return False
            
            ws_uri = f"{self.ws_url}{self.wxid}"
            logger.info(f"正在连接WebSocket: {ws_uri}")
            
            # 设置超时时间和保持连接参数
            self.websocket = await websockets.connect(
                ws_uri,
                ping_interval=30,
                ping_timeout=10,
                close_timeout=5
            )
            
            logger.info("WebSocket连接成功")
            
            # 初始化消息API
            self.msg_api = MsgApi(self.base_url, self.wxid)
            self.current_reconnect_attempt = 0  # 重置重连计数
            
            return True
        except Exception as e:
            logger.error(f"WebSocket连接失败: {e}")
            return False
    
    async def handle_message(self, message_data: Dict[str, Any]):
        """处理接收到的消息"""
        try:
            # 解析消息 - 尝试多种可能的字段名
            msg_id = message_data.get("msgId")
            msg_type = message_data.get("category", message_data.get("category", 0))
            is_group = '@chatroom' in message_data.get('sender', {}).get('id', '')
            org_content = message_data.get("content", message_data.get("Content", ""))
            content = org_content
            nick_name = config_manager.get("config", 'nickname', '布里茨')
            is_at = '@' + nick_name in org_content
            sender_wxid = message_data.get('sender', {}).get('id', '')
            from_wxid = message_data.get('sender', {}).get('id', '')
            sender_nickname = ''
            from_nickname = ''
            at_names = ''

            if is_group:
                from_wxid = message_data.get('sender', {}).get('id', '')
                sender_wxid = content.split(':\n')[0] if ':\n' in content else sender_wxid
                at_names = ','.join(re.findall(r'@([^\u2005]+)', content))
                # 处理群消息内容，移除发送者ID前缀
                if ':' in content:
                    content_parts = content.split(':\n', 1)
                    if len(content_parts) > 1:
                        content = content_parts[1].split('\u2005')[-1] if '\u2005' in content_parts[1] else content_parts[1]
            frend_api=FriendApi.init()
            # 获取联系人信息
            batch_data = await frend_api.friend_get_contract_detail(towxids=f'{sender_wxid},{from_wxid}')

            # 安全地提取联系人列表，避免None错误
            contact_list = []
            if batch_data and isinstance(batch_data, dict):
                data = batch_data.get('Data')
                if data and isinstance(data, dict):
                    contact_list = data.get('ContactList', [])
            # 处理联系人信息
            if contact_list and isinstance(contact_list, list):
                for contact in contact_list:
                    if not isinstance(contact, dict):
                        continue
                    contact_wxid = contact.get('UserName', {}).get('string', '')
                    nick_name = contact.get('NickName', {}).get('string', '')
                    if contact_wxid == sender_wxid:
                        sender_nickname = nick_name
                        #构建好友信息
                        await self.db.save_friend_info(wxid=sender_wxid, nickname=nick_name, remark=contact.get('Remark', {}).get('string', '') if isinstance(contact.get('Remark', {}), dict) else '',avatar_url=contact.get('SmallHeadImgUrl',''))
                    if contact_wxid == from_wxid:
                        from_nickname = nick_name

                    # 处理群成员信息
                    chat_room_member = contact.get('NewChatroomData', {}).get('ChatRoomMember', [])
                    if chat_room_member and isinstance(chat_room_member, list):
                        await self.db.save_group_info(qid=contact_wxid,group_name=from_nickname, owner_wxid=contact.get('ChatRoomOwner', ''), member_count=len(chat_room_member), member_list=chat_room_member)
                        for member in chat_room_member:
                            if isinstance(member, dict) and member.get('UserName', '') == sender_wxid:
                                sender_nickname = member.get('NickName', sender_nickname)
                                break

            message = Message(
                msg_id=msg_id,
                sender_wxid=sender_wxid,
                sender_nickname=sender_nickname,
                from_wxid=from_wxid,
                from_nickname=from_nickname,
                msg_type=msg_type,
                org_content=org_content,
                content=content,
                is_group=is_group,
                timestamp=datetime.now(),
                at_names=at_names,
                is_at=is_at,
                new_msg_id=msg_id
            )

            # 保存消息到数据库
            try:
                await self.db.save_message(message)
            except Exception as db_e:
                logger.error(f"保存消息到数据库失败:",db_e)
            logger.info(f"收到消息: {message.__dict__}")
            # 调用插件处理消息
            try:
                response = await self.plugin_manager.process_message(message,self.msg_api)
                # 如果有响应消息，发送出去
                if response:
                    await self._send_response(response, from_wxid)
            except Exception as plugin_e:
                logger.error(f"插件处理消息失败:",plugin_e)
        except Exception as e:
            logger.error(f"处理消息失败:",e)
            logger.error(f"消息数据: {message_data}")

    
    async def _send_response(self, response: Dict[str, Any], to_wxid: str):
        """发送响应消息"""
        try:
            response_type = response.get("type", "text")
            content = response.get("content", "")
            
            # 检查msg_api是否可用
            if not self.msg_api:
                logger.error("消息API未初始化，无法发送响应")
                return
                
            if response_type == "text":
                await self.msg_api.msg_send_txt(self.wxid, to_wxid, content)
            elif response_type == "image":
                await self.msg_api.msg_send_cdn_img(self.wxid, to_wxid, content)
            elif response_type == "file":
                await self.msg_api.msg_send_cdn_file(self.wxid, to_wxid, content)
            else:
                logger.warning(f"不支持的响应类型: {response_type}")
                
        except Exception as e:
            logger.error(f"发送响应消息失败: {e}")
    
    async def listen_messages(self):
        """监听WebSocket消息"""
        try:
            while self.running and self.websocket:
                try:
                    message = await asyncio.wait_for(self.websocket.recv(), timeout=60)
                    
                    # 检查连接状态
                    if isinstance(message, str) and ("已关闭连接" in message or "connection closed" in message.lower()):
                        logger.info("检测到服务端主动关闭连接，准备重连...")
                        break
                    
                    # 处理连接确认消息
                    if isinstance(message, str) and "已连接" in message:
                        logger.info(f"WebSocket连接确认: {message}")
                        continue
                    
                    # 解析JSON消息
                    try:
                        message_data = json.loads(message)
                        await self.handle_message(message_data)
                    except json.JSONDecodeError:
                        # 如果不是JSON格式，可能是系统消息或其他格式
                        if isinstance(message, str):
                            if message.startswith('<sysmsg'):
                                logger.info(f"收到系统消息: {message[:100]}...")
                            elif message.startswith('<msg>'):
                                logger.info(f"收到XML消息: {message[:100]}...")
                            else:
                                logger.info(f"收到文本消息: {message}")
                        else:
                            logger.warning(f"无法解析的消息格式: {type(message)}")
                        
                except asyncio.TimeoutError:
                    # 发送ping来检查连接是否仍然有效
                    try:
                        await self.websocket.ping()
                    except:
                        logger.warning("ping失败，连接可能已断开")
                        break
                except websockets.exceptions.ConnectionClosed as cc:
                    logger.error(f"WebSocket连接已关闭: {cc}")
                    break
                except Exception as e:
                    logger.error(f"接收消息异常: {e}")
                    break
                    
        except Exception as e:
            logger.error(f"监听消息异常: {e}")
        finally:
            # 如果还在运行状态，尝试重连
            if self.running:
                await self.try_reconnect()
    
    async def try_reconnect(self):
        """尝试重新连接WebSocket"""
        if not self.running:
            return
            
        if self.current_reconnect_attempt < self.max_reconnect_attempts:
            self.current_reconnect_attempt += 1
            wait_time = self.reconnect_interval * (1.5 ** min(self.current_reconnect_attempt, 5))
            
            logger.info(f"尝试第 {self.current_reconnect_attempt}/{self.max_reconnect_attempts} 次重连，等待 {wait_time:.1f} 秒...")
            
            # 关闭旧的WebSocket连接
            if self.websocket:
                try:
                    await self.websocket.close()
                except:
                    pass
                self.websocket = None
            
            await asyncio.sleep(wait_time)
            
            # 尝试重新连接
            if await self.connect_websocket():
                logger.info("重连成功！")
                # 重新开始监听
                asyncio.create_task(self.listen_messages())
            else:
                logger.error("重连失败！")
                # 递归尝试下一次重连
                await self.try_reconnect()
        else:
            logger.error(f"达到最大重连次数 {self.max_reconnect_attempts}，停止重连")
            self.running = False
    
    async def run(self):
        """运行客户端"""
        try:
            self.running = True
            
            # 初始化
            await self.initialize()
            
            # 等待管理后台完成登录
            if not await self.wait_for_login():
                logger.error("等待登录失败，程序退出")
                return
            
            # 连接WebSocket
            if not await self.connect_websocket():
                logger.error("连接WebSocket失败，程序退出")
                return
            
            # 开始监听消息
            await self.listen_messages()
            
        except KeyboardInterrupt:
            logger.info("收到中断信号，正在退出...")
        except Exception as e:
            logger.error(f"程序运行异常: {e}")
        finally:
            self.running = False
            # 清理资源
            if self.websocket:
                await self.websocket.close()
            await self.db.close()
            logger.info("程序已退出")

